import os
import uuid
import mimetypes
from pathlib import Path
from typing import Dict, Any, Tuple
from fastapi import UploadFile, HTTPException

from log import log_info, log_error


# 文件存储配置
UPLOAD_DIR = Path("static/personal_documents")
ALLOWED_EXTENSIONS = {
    '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', 
    '.txt', '.md', '.rtf', '.odt', '.ods', '.odp',
    '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg',
    '.zip', '.rar', '.7z', '.tar', '.gz'
}
MAX_FILE_SIZE = 50 * 1024 * 1024  # 50MB

# 文件类型图标和颜色映射
FILE_TYPE_INFO = {
    'pdf': {'icon': '📄', 'color': '#dc3545', 'name': 'PDF文档'},
    'doc': {'icon': '📝', 'color': '#2b579a', 'name': 'Word文档'},
    'docx': {'icon': '📝', 'color': '#2b579a', 'name': 'Word文档'},
    'xls': {'icon': '📊', 'color': '#217346', 'name': 'Excel表格'},
    'xlsx': {'icon': '📊', 'color': '#217346', 'name': 'Excel表格'},
    'ppt': {'icon': '📽️', 'color': '#d24726', 'name': 'PowerPoint演示'},
    'pptx': {'icon': '📽️', 'color': '#d24726', 'name': 'PowerPoint演示'},
    'txt': {'icon': '📃', 'color': '#6c757d', 'name': '文本文件'},
    'md': {'icon': '📋', 'color': '#0969da', 'name': 'Markdown文档'},
    'rtf': {'icon': '📝', 'color': '#6f42c1', 'name': 'RTF文档'},
    'odt': {'icon': '📝', 'color': '#0066cc', 'name': 'OpenDocument文本'},
    'ods': {'icon': '📊', 'color': '#0066cc', 'name': 'OpenDocument表格'},
    'odp': {'icon': '📽️', 'color': '#0066cc', 'name': 'OpenDocument演示'},
    'jpg': {'icon': '🖼️', 'color': '#fd7e14', 'name': '图片文件'},
    'jpeg': {'icon': '🖼️', 'color': '#fd7e14', 'name': '图片文件'},
    'png': {'icon': '🖼️', 'color': '#fd7e14', 'name': '图片文件'},
    'gif': {'icon': '🖼️', 'color': '#fd7e14', 'name': '图片文件'},
    'bmp': {'icon': '🖼️', 'color': '#fd7e14', 'name': '图片文件'},
    'svg': {'icon': '🖼️', 'color': '#fd7e14', 'name': '矢量图片'},
    'zip': {'icon': '🗜️', 'color': '#6f42c1', 'name': '压缩文件'},
    'rar': {'icon': '🗜️', 'color': '#6f42c1', 'name': '压缩文件'},
    '7z': {'icon': '🗜️', 'color': '#6f42c1', 'name': '压缩文件'},
    'tar': {'icon': '🗜️', 'color': '#6f42c1', 'name': '压缩文件'},
    'gz': {'icon': '🗜️', 'color': '#6f42c1', 'name': '压缩文件'},
    'default': {'icon': '📄', 'color': '#6c757d', 'name': '未知文件'}
}


def ensure_upload_dir() -> None:
    """确保上传目录存在"""
    try:
        UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
        log_info(f"确保上传目录存在: {UPLOAD_DIR}", module="core.document.file_storage")
    except Exception as e:
        log_error(f"创建上传目录失败: {str(e)}", exc_info=True, module="core.document.file_storage")
        raise


def validate_file(file: UploadFile) -> None:
    """验证上传文件"""
    try:
        # 检查文件大小
        if hasattr(file, 'size') and file.size and file.size > MAX_FILE_SIZE:
            raise HTTPException(
                status_code=413,
                detail=f"文件大小超过限制 ({MAX_FILE_SIZE / 1024 / 1024:.1f}MB)"
            )
        
        # 检查文件扩展名
        if file.filename:
            file_ext = Path(file.filename).suffix.lower()
            if file_ext not in ALLOWED_EXTENSIONS:
                raise HTTPException(
                    status_code=400,
                    detail=f"不支持的文件类型: {file_ext}"
                )
        else:
            raise HTTPException(status_code=400, detail="文件名不能为空")
        
        log_info(f"文件验证通过: {file.filename}", module="core.document.file_storage")
        
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"文件验证失败: {str(e)}", exc_info=True, module="core.document.file_storage")
        raise HTTPException(status_code=400, detail="文件验证失败")


def generate_unique_filename(original_filename: str) -> str:
    """生成唯一文件名"""
    try:
        file_path = Path(original_filename)
        file_ext = file_path.suffix.lower()
        unique_name = f"{uuid.uuid4().hex}{file_ext}"
        
        log_info(f"生成唯一文件名: {original_filename} -> {unique_name}", module="core.document.file_storage")
        return unique_name
        
    except Exception as e:
        log_error(f"生成文件名失败: {str(e)}", exc_info=True, module="core.document.file_storage")
        raise


def get_file_type_from_extension(filename: str) -> str:
    """根据文件扩展名获取文件类型"""
    try:
        file_ext = Path(filename).suffix.lower().lstrip('.')
        return file_ext if file_ext else 'unknown'
    except Exception:
        return 'unknown'


def get_file_type_info(file_type: str) -> Dict[str, str]:
    """获取文件类型信息（图标、颜色、名称）"""
    return FILE_TYPE_INFO.get(file_type, FILE_TYPE_INFO['default'])


async def save_uploaded_file(file: UploadFile) -> Tuple[str, Dict[str, Any]]:
    """保存上传的文件并返回文件信息"""
    try:
        log_info(f"开始保存文件: {file.filename}", module="core.document.file_storage")
        
        # 确保上传目录存在
        ensure_upload_dir()
        
        # 验证文件
        validate_file(file)
        
        # 生成唯一文件名
        unique_filename = generate_unique_filename(file.filename)
        file_path = UPLOAD_DIR / unique_filename
        
        # 保存文件
        content = await file.read()
        with open(file_path, "wb") as f:
            f.write(content)
        
        # 获取文件信息
        file_size = len(content)
        file_type = get_file_type_from_extension(file.filename)
        mime_type = mimetypes.guess_type(file.filename)[0]
        
        file_info = {
            'filename': file.filename,
            'file_path': str(file_path),
            'file_size': file_size,
            'file_type': file_type,
            'mime_type': mime_type
        }
        
        log_info(f"文件保存成功: {file_path} ({file_size} bytes)", module="core.document.file_storage")
        return str(file_path), file_info
        
    except HTTPException:
        raise
    except Exception as e:
        log_error(f"保存文件失败: {str(e)}", exc_info=True, module="core.document.file_storage")
        raise HTTPException(status_code=500, detail="文件保存失败")


async def delete_file(file_path: str) -> bool:
    """删除文件"""
    try:
        if os.path.exists(file_path):
            os.remove(file_path)
            log_info(f"文件删除成功: {file_path}", module="core.document.file_storage")
            return True
        else:
            log_info(f"文件不存在，跳过删除: {file_path}", module="core.document.file_storage")
            return False
            
    except Exception as e:
        log_error(f"删除文件失败: {str(e)}", exc_info=True, module="core.document.file_storage")
        return False


def get_file_info(file_path: str) -> Dict[str, Any]:
    """获取文件信息"""
    try:
        if not os.path.exists(file_path):
            raise FileNotFoundError("文件不存在")
        
        stat = os.stat(file_path)
        file_type = get_file_type_from_extension(file_path)
        type_info = get_file_type_info(file_type)
        
        return {
            'size': stat.st_size,
            'type': file_type,
            'type_info': type_info,
            'modified_time': stat.st_mtime,
            'exists': True
        }
        
    except Exception as e:
        log_error(f"获取文件信息失败: {str(e)}", module="core.document.file_storage")
        return {'exists': False}


def format_file_size(size_bytes: int) -> str:
    """格式化文件大小显示"""
    try:
        if size_bytes == 0:
            return "0 B"
        
        size_names = ["B", "KB", "MB", "GB", "TB"]
        import math
        i = int(math.floor(math.log(size_bytes, 1024)))
        p = math.pow(1024, i)
        s = round(size_bytes / p, 2)
        
        return f"{s} {size_names[i]}"
        
    except Exception:
        return f"{size_bytes} B"
